/*
 * 
 * 
 * 
 */
package com.hboxs.asl.service.impl;

import com.hboxs.asl.*;
import com.hboxs.asl.dao.*;
import com.hboxs.asl.entity.*;
import com.hboxs.asl.entity.Order;
import com.hboxs.asl.entity.Order.OrderStatus;
import com.hboxs.asl.entity.Order.PaymentStatus;
import com.hboxs.asl.entity.Order.ShippingStatus;
import com.hboxs.asl.entity.OrderLog.Type;
import com.hboxs.asl.pingpp.Constants;
import com.hboxs.asl.service.OrderService;
import com.hboxs.asl.util.SettingUtils;
import com.pingplusplus.model.Charge;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.persistence.LockModeType;
import java.math.BigDecimal;
import java.util.*;

/**
 * Service - 订单
 */
@Service("orderServiceImpl")
public class OrderServiceImpl extends BaseServiceImpl<Order, Long> implements OrderService {

    @Resource(name = "orderDaoImpl")
    private OrderDao orderDao;
    @Resource(name = "orderItemDaoImpl")
    private OrderItemDao orderItemDao;
    @Resource(name = "orderLogDaoImpl")
    private OrderLogDao orderLogDao;
    @Resource(name = "cartDaoImpl")
    private CartDao cartDao;
    @Resource(name = "couponCodeDaoImpl")
    private CouponCodeDao couponCodeDao;
    @Resource(name = "snDaoImpl")
    private SnDao snDao;
    @Resource(name = "memberDaoImpl")
    private MemberDao memberDao;
    @Resource(name = "productDaoImpl")
    private ProductDao productDao;
    @Resource(name = "depositDaoImpl")
    private DepositDao depositDao;
    @Resource(name = "paymentDaoImpl")
    private PaymentDao paymentDao;
    @Resource(name = "refundsDaoImpl")
    private RefundsDao refundsDao;
    @Resource(name = "shippingDaoImpl")
    private ShippingDao shippingDao;
    @Resource(name = "returnsDaoImpl")
    private ReturnsDao returnsDao;
    @Resource(name = "cartItemDaoImpl")
    private CartItemDao cartItemDao;
    @Resource(name = "promotionDaoImpl")
    private PromotionDao promotionDao;
    @Resource(name = "paymentMethodDaoImpl")
    private PaymentMethodDao paymentMethodDao;
    @Resource(name = "shippingMethodDaoImpl")
    private ShippingMethodDao shippingMethodDao;
    @Resource(name = "platformDaoImpl")
    private PlatformDao platformDao;
    @Resource(name = "merchantDaoImpl")
    private MerchantDao merchantDao;
    @Resource(name = "pointTradeDaoImpl")
    private PointTradeDao pointTradeDao;
    @Resource(name = "anchorTradeDaoImpl")
    private AnchorTradeDao anchorTradeDao;
    @Resource(name = "globalConfigDaoImpl")
    private GlobalConfigDao globalConfigDao;

    @Resource(name = "orderDaoImpl")
    public void setBaseDao(OrderDao orderDao) {
        super.setBaseDao(orderDao);
    }

    @Transactional(readOnly = true)
    public Order findBySn(String sn) {
        return orderDao.findBySn(sn);
    }

    @Transactional(readOnly = true)
    public List<Order> findList(Member member, Integer count, List<Filter> filters, List<com.hboxs.asl.Order> orders) {
        return orderDao.findList(member, count, filters, orders);
    }

    @Transactional(readOnly = true)
    public Page<Order> findPage(Member member, Pageable pageable) {
        return orderDao.findPage(member, pageable);
    }

    @Transactional(readOnly = true)
    public Page<Order> findPage(OrderStatus orderStatus, PaymentStatus paymentStatus, ShippingStatus shippingStatus, Boolean hasExpired, Pageable pageable) {
        return orderDao.findPage(orderStatus, paymentStatus, shippingStatus, hasExpired, pageable);
    }

    @Transactional(readOnly = true)
    public Page<Order> findPage(Member member, Pageable pageable, int status) {
        List<com.hboxs.asl.Order> orders = pageable.getOrders();
        orders.add(com.hboxs.asl.Order.desc("createDate"));
        OrderStatus orderStatus = null;
        PaymentStatus paymentStatus = null;
        ShippingStatus shippingStatus = null;
        //其他状态显示未过期的
        Boolean hasExpired = false;
        //已完成订单去除已评论
        Boolean hasReview = null;
        //待收货去除已申请退换货
        Boolean hasApplyReturn = null;
        switch (status) {
            //待支付
            case 0:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.unpaid;
                shippingStatus = ShippingStatus.unshipped;
                break;
            //待发货
            case 1:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.unshipped;
                break;
            //退换货（排除未收货）
            case 2:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.shipped;
                hasApplyReturn = true;
                break;
            //已完成
            case 3:
                orderStatus = OrderStatus.completed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.shipped;
                hasReview = false;
                break;
            //全部订单的话显示,包含过期和未过期
            case 4:
                hasExpired = null;
                break;
            //待收货（全部为未申请退换货）
            case 5:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.shipped;
                hasApplyReturn = false;
                break;
            default:
                break;
        }
        return orderDao.findPage(member, orderStatus, paymentStatus, shippingStatus, hasExpired, hasReview, hasApplyReturn, pageable);
    }

    @Transactional(readOnly = true)
    public Long count(OrderStatus orderStatus, PaymentStatus paymentStatus, ShippingStatus shippingStatus, Boolean hasExpired) {
        return orderDao.count(orderStatus, paymentStatus, shippingStatus, hasExpired);
    }

    @Transactional(readOnly = true)
    public Long count(Member member, int status) {
        OrderStatus orderStatus = null;
        PaymentStatus paymentStatus = null;
        ShippingStatus shippingStatus = null;
        Boolean hasExpired = false;
        Boolean hasReview = null;
        Boolean hasApplyReturn = null;
        switch (status) {
            //待支付
            case 0:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.unpaid;
                shippingStatus = ShippingStatus.unshipped;
                break;
            //待发货
            case 1:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.unshipped;
                break;
            //退换货（未收货，包含已申请退换货的订单）
            case 2:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.shipped;
                hasApplyReturn = true;
                break;
            //已完成
            case 3:
                orderStatus = OrderStatus.completed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.shipped;
                hasReview = false;
                break;
            //全部订单的话显示,包含过期和未过期
            case 4:
                hasExpired = null;
                break;
            //待收货（全部为未申请退换货）
            case 5:
                orderStatus = OrderStatus.confirmed;
                paymentStatus = PaymentStatus.paid;
                shippingStatus = ShippingStatus.shipped;
                hasApplyReturn = false;
                break;
            default:
                break;
        }
        return orderDao.count(member, orderStatus, paymentStatus, shippingStatus, hasExpired, hasReview, hasApplyReturn);
    }

    @Transactional(readOnly = true)
    public Long waitingPaymentCount(Member member) {
        return orderDao.waitingPaymentCount(member);
    }

    @Transactional(readOnly = true)
    public Long waitingShippingCount(Member member) {
        return orderDao.waitingShippingCount(member);
    }

    @Transactional(readOnly = true)
    public BigDecimal getSalesAmount(Date beginDate, Date endDate) {
        return orderDao.getSalesAmount(beginDate, endDate);
    }

    @Transactional(readOnly = true)
    public BigDecimal getPaySalesAmount(Date beginDate, Date endDate) {
        return orderDao.getPaySalesAmount(beginDate, endDate);
    }

    @Transactional(readOnly = true)
    public Integer getSalesVolume(Date beginDate, Date endDate) {
        return orderDao.getSalesVolume(beginDate, endDate);
    }

    public void releaseStock() {
        orderDao.releaseStock();
    }

    @Transactional(readOnly = true)
    public List<Order> build(Cart cart, Receiver receiver, PaymentMethod paymentMethod, CouponCode couponCode, boolean isInvoice, String invoiceTitle,
                             boolean useBalance, BigDecimal balance, Map<Long, String> memoJson) {
        Assert.notNull(cart);
        Assert.notNull(cart.getMember());
        Assert.notEmpty(cart.getCartItems());


        List<Merchant> merchants = cart.getMerchants();
        List<Order> orders = new ArrayList<Order>();

        for (Merchant merchant : merchants) {

            if (cart.getCartItems(merchant).size() == 0) {
                continue;
            }

            Order order = new Order();
            order.setMerchant(merchant);
            order.setShippingStatus(ShippingStatus.unshipped);
            order.setFee(new BigDecimal(0));
            order.setPromotionDiscount(new BigDecimal(0));
            order.setCouponDiscount(new BigDecimal(0));
            order.setOffsetAmount(new BigDecimal(0));

            order.setPoint(cart.getEffectivePoint(merchant));
            order.setmPoint(cart.getEffectivemPoint(merchant));
            if (memoJson != null) {
                order.setMemo(memoJson.get(merchant.getId()) == null ? "" : memoJson.get(merchant.getId()));
            }
            order.setMember(cart.getMember());


            if (receiver != null) {
                order.setConsignee(receiver.getConsignee());
                order.setAreaName(receiver.getAreaName());
                order.setAddress(receiver.getAddress());
                order.setZipCode(receiver.getZipCode());
                order.setPhone(receiver.getPhone());
                order.setArea(receiver.getArea());
            }

            order.setPaymentMethod(paymentMethod);

            ShippingMethod shippingMethod = shippingMethodDao.findDefault(merchant);
            if (shippingMethod != null) {
                //有效重量
                int weight = cart.getWeight(merchant);
                BigDecimal freight = shippingMethod.calculateFreight(weight);
                order.setFreight(freight);
                order.setShippingMethod(shippingMethod);
            } else {
                order.setFreight(new BigDecimal(0));
            }

            if (couponCode != null) {
                couponCodeDao.lock(couponCode, LockModeType.PESSIMISTIC_WRITE);
                if (!couponCode.getIsUsed() && couponCode.getCoupon() != null && cart.isValid(couponCode.getCoupon())) {
                    BigDecimal couponDiscount = couponCode.getCoupon().getCut();

                    // 优惠券按照订单价格比例分配
                    couponDiscount = couponDiscount.compareTo(new BigDecimal(0)) > 0 ? couponDiscount.multiply(cart.getPrice(merchant).divide(cart.getPrice(), 2, BigDecimal.ROUND_HALF_UP)).setScale(2, BigDecimal.ROUND_HALF_UP) : new BigDecimal(0);
                    order.setCouponDiscount(couponDiscount);
                    order.setCouponCode(couponCode);
                }
            }

            List<OrderItem> orderItems = order.getOrderItems();
            for (CartItem cartItem : cart.getCartItems(merchant)) {
                Product product = cartItem.getProduct();
                orderItems.add(orderItemDao.generate(product, cartItem, order));
            }

            Setting setting = SettingUtils.get();
            if (setting.getIsInvoiceEnabled() && isInvoice && StringUtils.isNotEmpty(invoiceTitle)) {
                order.setIsInvoice(true);
                order.setInvoiceTitle(invoiceTitle);
                order.setTax(order.calculateTax());
            } else {
                order.setIsInvoice(false);
                order.setTax(new BigDecimal(0));
            }

            if (useBalance) {
                if (balance.compareTo(order.getAmount()) >= 0) {
                    order.setAmountPaid(order.getAmount());
                } else {
                    order.setAmountPaid(balance);
                }
            } else {
                order.setAmountPaid(new BigDecimal(0));
            }

            if (order.getAmountPayable().compareTo(new BigDecimal(0)) == 0) {
                order.setOrderStatus(OrderStatus.confirmed);
                order.setPaymentStatus(PaymentStatus.paid);
            } else if (order.getAmountPayable().compareTo(new BigDecimal(0)) > 0 && order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
                order.setOrderStatus(OrderStatus.confirmed);
                order.setPaymentStatus(PaymentStatus.partialPayment);
            } else {
                order.setOrderStatus(OrderStatus.unconfirmed);
                order.setPaymentStatus(PaymentStatus.unpaid);
            }

            if (paymentMethod != null && paymentMethod.getTimeout() != null && order.getPaymentStatus() == PaymentStatus.unpaid) {
                order.setExpire(DateUtils.addMinutes(new Date(), paymentMethod.getTimeout()));
            }

            // 促销
            dealPromotion(order);

            orders.add(order);
        }

        return orders;
    }


    @Transactional(readOnly = true)
    public Order build(Cart cart, Receiver receiver, PaymentMethod paymentMethod, ShippingMethod shippingMethod, CouponCode couponCode, boolean isInvoice, String invoiceTitle,
                       boolean useBalance, BigDecimal balance, String memo) {

        Assert.notNull(cart);
        Assert.notNull(cart.getMember());
        Assert.notEmpty(cart.getCartItems());


        if (!cart.ifExistAdmin()) {
            return null;
        }

        Order order = new Order();

        order.setMerchant(Merchant.generateAdminMerchant());
        order.setShippingStatus(ShippingStatus.unshipped);
        order.setFee(new BigDecimal(0));
        order.setPromotionDiscount(new BigDecimal(0));
        order.setCouponDiscount(new BigDecimal(0));
        order.setOffsetAmount(new BigDecimal(0));

        order.setPoint(cart.getEffectivePoint());
        order.setmPoint(cart.getEffectivePoint());
        order.setMemo(memo);
        order.setMember(cart.getMember());


        if (receiver != null) {
            order.setConsignee(receiver.getConsignee());
            order.setAreaName(receiver.getAreaName());
            order.setAddress(receiver.getAddress());
            order.setZipCode(receiver.getZipCode());
            order.setPhone(receiver.getPhone());
            order.setArea(receiver.getArea());
        }

        order.setPaymentMethod(paymentMethod);

        if (shippingMethod != null) {
            //有效重量
            int weight = cart.getWeight();
            BigDecimal freight = shippingMethod.calculateFreight(weight);
            order.setFreight(freight);
            order.setShippingMethod(shippingMethod);
        } else {
            order.setFreight(new BigDecimal(0));
        }

        if (couponCode != null) {
            couponCodeDao.lock(couponCode, LockModeType.PESSIMISTIC_WRITE);
            if (!couponCode.getIsUsed() && couponCode.getCoupon() != null && cart.isValid(couponCode.getCoupon())) {
                BigDecimal couponDiscount = couponCode.getCoupon().getCut();

                // 优惠券按照订单价格比例分配
                couponDiscount = couponDiscount.compareTo(new BigDecimal(0)) > 0 ? couponDiscount.multiply(cart.getPrice(null).divide(cart.getPrice(), 2, BigDecimal.ROUND_HALF_UP)).setScale(2, BigDecimal.ROUND_HALF_UP) : new BigDecimal(0);
                order.setCouponDiscount(couponDiscount);
                order.setCouponCode(couponCode);
            }
        }

        List<OrderItem> orderItems = order.getOrderItems();
        for (CartItem cartItem : cart.getCartItems()) {
            if (cartItem != null && cartItem.getProduct() != null && cartItem.getIsSelected() && cartItem.getProduct().getMerchant() == null) {
                Product product = cartItem.getProduct();
                orderItems.add(orderItemDao.generate(product, cartItem, order));
            }
        }

        Setting setting = SettingUtils.get();
        if (setting.getIsInvoiceEnabled() && isInvoice && StringUtils.isNotEmpty(invoiceTitle)) {
            order.setIsInvoice(true);
            order.setInvoiceTitle(invoiceTitle);
            order.setTax(order.calculateTax());
        } else {
            order.setIsInvoice(false);
            order.setTax(new BigDecimal(0));
        }

        if (useBalance) {
            if (balance.compareTo(order.getAmount()) >= 0) {
                order.setAmountPaid(order.getAmount());
            } else {
                order.setAmountPaid(balance);
            }
        } else {
            order.setAmountPaid(new BigDecimal(0));
        }

        if (order.getAmountPayable().compareTo(new BigDecimal(0)) == 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.paid);
        } else if (order.getAmountPayable().compareTo(new BigDecimal(0)) > 0 && order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.partialPayment);
        } else {
            order.setOrderStatus(OrderStatus.unconfirmed);
            order.setPaymentStatus(PaymentStatus.unpaid);
        }

        if (paymentMethod != null && paymentMethod.getTimeout() != null && order.getPaymentStatus() == PaymentStatus.unpaid) {
            order.setExpire(DateUtils.addMinutes(new Date(), paymentMethod.getTimeout()));
        }

        // 促销
        dealPromotion(order);

        return order;
    }


    public List<Order> create(Cart cart, Receiver receiver, PaymentMethod paymentMethod, ShippingMethod shippingMethod,
                              CouponCode couponCode, boolean isInvoice, String invoiceTitle, boolean useBalance, BigDecimal balance,
                              Map<Long, String> memoMap, Admin operator) {
        Assert.notNull(cart);
        Assert.notNull(cart.getMember());
        Assert.notEmpty(cart.getCartItems());
        Assert.notNull(receiver);
        Assert.notNull(paymentMethod);

        List<Order> orders = build(cart, receiver, paymentMethod, couponCode, isInvoice, invoiceTitle, useBalance, balance, memoMap);
        Order adminOrder = build(cart, receiver, paymentMethod, shippingMethod, couponCode, isInvoice,
                invoiceTitle, useBalance, balance, memoMap != null ? memoMap.get(0l) : null);

        if (adminOrder != null) {
            // 清理build自营订单里面的虚拟商家
            adminOrder.setMerchant(null);
            orders.add(adminOrder);
        }

        for (Order order : orders) {
            order.setSn(snDao.generate(Sn.Type.order));
            if (paymentMethod.getMethod() == PaymentMethod.Method.online) {
                order.setLockExpire(DateUtils.addSeconds(new Date(), 20));
                order.setOperator(operator);
            }

            if (order.getCouponCode() != null) {
                couponCode.setIsUsed(true);
                couponCode.setUsedDate(new Date());
                couponCodeDao.merge(couponCode);
            }

            Setting setting = SettingUtils.get();
            if (setting.getStockAllocationTime() == Setting.StockAllocationTime.order || (setting.getStockAllocationTime() == Setting.StockAllocationTime.payment && (order.getPaymentStatus() == PaymentStatus.partialPayment || order.getPaymentStatus() == PaymentStatus.paid))) {
                order.setIsAllocatedStock(true);
            } else {
                order.setIsAllocatedStock(false);
            }

            // 判断积分是否大于订单金额
            if (order.getPayPoint() == null) {
                order.setPayPoint(new BigDecimal(0));
            } else {
                if (order.getPayPoint().compareTo(order.getAmountPayable().multiply(Constant.POINT_SCALE)) > 0)
                    order.setPayPoint(order.getAmountPayable().multiply(Constant.POINT_SCALE));
            }

            Member member = cart.getMember();

            //自动确认订单
            order.setOrderStatus(OrderStatus.confirmed);
            orderDao.persist(order);
            orderLogDao.generateOrderLog(Type.create, operator != null ? operator.getUsername() : member.getUsername(), order);

            if (order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
                memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
                member.setBalance(member.getBalance().subtract(order.getAmountPaid()));
                memberDao.merge(member);

                Deposit.Type type = operator != null ? Deposit.Type.adminPayment : Deposit.Type.memberPayment;
                String operatorStr = (operator != null ? operator.getUsername() : null);

                depositDao.generate(type, new BigDecimal(0), order.getAmountPaid(), operatorStr, null, member, order, null);
            }

            if (setting.getStockAllocationTime() == Setting.StockAllocationTime.order || (setting.getStockAllocationTime() == Setting.StockAllocationTime.payment && (order.getPaymentStatus() == PaymentStatus.partialPayment || order.getPaymentStatus() == PaymentStatus.paid))) {
                for (OrderItem orderItem : order.getOrderItems()) {
                    if (orderItem != null) {
                        Product product = orderItem.getProduct();
                        productDao.lock(product, LockModeType.PESSIMISTIC_WRITE);
                        if (product != null && product.getStock() != null) {
                            product.setAllocatedStock(product.getAllocatedStock() + (orderItem.getQuantity() - orderItem.getShippedQuantity()));
                            productDao.merge(product);
                            orderDao.flush();
                        }
                    }
                }
            }
        }

        Iterator<CartItem> it = cart.getCartItems().iterator();
        while (it.hasNext()) {
            CartItem ci = it.next();
            if (ci.getIsSelected()) {
                it.remove();
                cartItemDao.remove(ci);
            }
        }
        cartDao.merge(cart);
        if (cart.getCartItems().size() == 0) {
            cartDao.remove(cart);
        }

        return orders;
    }


    @Override
    public void dealMerchantPromotion(Order order) {

        for (Promotion p : promotionDao.findUsingList()) {
            switch (p.getType()) {

                // 包邮
                case freeShipping:
                    if (p.getMinimumPrice().compareTo(order.getSubtotalWithPromotion(p)) <= 0) {
                        order.setFreight(new BigDecimal(0));
                        order.setPromotion(p);
                    }
                    break;


                // 满减
                case subtract:
                    if (p.getMinimumPrice().compareTo(order.getSubtotalWithPromotion(p)) <= 0) {
                        order.setPromotionDiscount(p.getCut());
                        order.setPromotion(p);
                    }
                    break;

            }
        }
    }

    @Override
    public void dealPromotion(Order order) {

        for (Promotion p : promotionDao.findUsingList(order.getMerchant())) {
            switch (p.getType()) {

                // 包邮
                case freeShipping:
                    if (p.getMinimumPrice().compareTo(order.getSubtotalWithPromotion(p)) <= 0) {
                        order.setFreight(new BigDecimal(0));
                        order.setPromotion(p);
                    }
                    break;


                // 满减
                case subtract:
                    if (p.getMinimumPrice().compareTo(order.getSubtotalWithPromotion(p)) <= 0) {
                        order.setPromotionDiscount(p.getCut());
                        order.setPromotion(p);
                    }
                    break;

            }
        }
    }

    public void update(Order order, Admin operator) {
        Assert.notNull(order);

        Order pOrder = orderDao.find(order.getId());

        if (pOrder.getIsAllocatedStock()) {
            deleteOrderItems(pOrder);
            deleteOrderItems(order);
        }
        orderDao.merge(order);
        orderLogDao.generateOrderLog(Type.modify, operator != null ? operator.getUsername() : null, order);
    }

    public void merchantUpdate(Order order, Merchant operatorMerchant) {
        Assert.notNull(order);

        Order pOrder = orderDao.find(order.getId());

        if (pOrder.getIsAllocatedStock()) {
            deleteOrderItems(pOrder);
            deleteOrderItems(order);
        }
        orderDao.merge(order);
        orderLogDao.generateOrderLog(Type.modify, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }


    public void confirm(Order order, Admin operator) {
        Assert.notNull(order);

        order.setOrderStatus(OrderStatus.confirmed);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.confirm, operator != null ? operator.getUsername() : null, order);
    }


    public void merchantConfirm(Order order, Merchant operatorMerchant) {
        Assert.notNull(order);

        order.setOrderStatus(OrderStatus.confirmed);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.confirm, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }

    public void complete(Order order, Admin operator) {
        Assert.notNull(order);

        Member member = order.getMember();
        memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);

        if (order.getShippingStatus() == ShippingStatus.partialShipment || order.getShippingStatus() == ShippingStatus.shipped) {
            member.setPoint(member.getPoint().add(order.getPoint()));
        }

        if (order.getShippingStatus() == ShippingStatus.unshipped || order.getShippingStatus() == ShippingStatus.returned) {
            CouponCode couponCode = order.getCouponCode();
            resetCouponCode(couponCode, order);
        }
        if (member.getAmount() == null) {
            member.setAmount(BigDecimal.ZERO);
        }
        member.setAmount(member.getAmount().add(order.getAmountPaid()));

        memberDao.merge(member);

        if (order.getIsAllocatedStock()) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(false);
        }

        for (OrderItem orderItem : order.getOrderItems()) {
            if (orderItem != null) {
                Product product = orderItem.getProduct();
                productDao.lock(product, LockModeType.PESSIMISTIC_WRITE);
                if (product != null) {
                    Integer quantity = orderItem.getQuantity();
                    Calendar nowCalendar = Calendar.getInstance();
                    Calendar weekSalesCalendar = DateUtils.toCalendar(product.getWeekSalesDate());
                    Calendar monthSalesCalendar = DateUtils.toCalendar(product.getMonthSalesDate());
                    if (nowCalendar.get(Calendar.YEAR) != weekSalesCalendar.get(Calendar.YEAR) || nowCalendar.get(Calendar.WEEK_OF_YEAR) > weekSalesCalendar.get(Calendar.WEEK_OF_YEAR)) {
                        product.setWeekSales((long) quantity);
                    } else {
                        product.setWeekSales(product.getWeekSales() + quantity);
                    }
                    if (nowCalendar.get(Calendar.YEAR) != monthSalesCalendar.get(Calendar.YEAR) || nowCalendar.get(Calendar.MONTH) > monthSalesCalendar.get(Calendar.MONTH)) {
                        product.setMonthSales((long) quantity);
                    } else {
                        product.setMonthSales(product.getMonthSales() + quantity);
                    }
                    product.setSales(product.getSales() + quantity);
                    product.setWeekSalesDate(new Date());
                    product.setMonthSalesDate(new Date());
                    productDao.merge(product);
                    orderDao.flush();
                }
            }
        }

        order.setCompleteDate(new Date());
        order.setOrderStatus(OrderStatus.completed);
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.complete, operator != null ? operator.getUsername() : null, order);
    }

    public void merchantComplete(Order order, Merchant operatorMerchant) {
        Assert.notNull(order);

        Member member = order.getMember();
        memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);

        if (order.getShippingStatus() == ShippingStatus.partialShipment || order.getShippingStatus() == ShippingStatus.shipped) {
            member.setPoint(member.getPoint().add(order.getPoint()));
        }

        if (order.getShippingStatus() == ShippingStatus.unshipped || order.getShippingStatus() == ShippingStatus.returned) {
            CouponCode couponCode = order.getCouponCode();
            resetCouponCode(couponCode, order);
        }
        if (member.getAmount() == null) {
            member.setAmount(BigDecimal.ZERO);
        }
        member.setAmount(member.getAmount().add(order.getAmountPaid()));

        memberDao.merge(member);

        if (order.getIsAllocatedStock()) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(false);
        }

        for (OrderItem orderItem : order.getOrderItems()) {
            if (orderItem != null) {
                Product product = orderItem.getProduct();
                productDao.lock(product, LockModeType.PESSIMISTIC_WRITE);
                if (product != null) {
                    Integer quantity = orderItem.getQuantity();
                    Calendar nowCalendar = Calendar.getInstance();
                    Calendar weekSalesCalendar = DateUtils.toCalendar(product.getWeekSalesDate());
                    Calendar monthSalesCalendar = DateUtils.toCalendar(product.getMonthSalesDate());
                    if (nowCalendar.get(Calendar.YEAR) != weekSalesCalendar.get(Calendar.YEAR) || nowCalendar.get(Calendar.WEEK_OF_YEAR) > weekSalesCalendar.get(Calendar.WEEK_OF_YEAR)) {
                        product.setWeekSales((long) quantity);
                    } else {
                        product.setWeekSales(product.getWeekSales() + quantity);
                    }
                    if (nowCalendar.get(Calendar.YEAR) != monthSalesCalendar.get(Calendar.YEAR) || nowCalendar.get(Calendar.MONTH) > monthSalesCalendar.get(Calendar.MONTH)) {
                        product.setMonthSales((long) quantity);
                    } else {
                        product.setMonthSales(product.getMonthSales() + quantity);
                    }
                    product.setSales(product.getSales() + quantity);
                    product.setWeekSalesDate(new Date());
                    product.setMonthSalesDate(new Date());
                    productDao.merge(product);
                    orderDao.flush();
                }
            }
        }

        order.setCompleteDate(new Date());
        order.setOrderStatus(OrderStatus.completed);
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.complete, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }


    public void cancel(Order order, Admin operator) {
        Assert.notNull(order);

        CouponCode couponCode = order.getCouponCode();
        resetCouponCode(couponCode, order);

        if (order.getIsAllocatedStock()) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(false);
        }

        order.setOrderStatus(OrderStatus.cancelled);
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.cancel, operator != null ? operator.getUsername() : null, order);
    }

    public void merchantCancel(Order order, Merchant operatorMerchant) {
        Assert.notNull(order);

        CouponCode couponCode = order.getCouponCode();
        resetCouponCode(couponCode, order);

        if (order.getIsAllocatedStock()) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(false);
        }

        order.setOrderStatus(OrderStatus.cancelled);
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.cancel, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }

    /**
     * 重置优惠码
     *
     * @param couponCode
     * @param order
     */
    private void resetCouponCode(CouponCode couponCode, Order order) {
        if (couponCode != null) {
            couponCode.setIsUsed(false);
            couponCode.setUsedDate(null);
            couponCodeDao.merge(couponCode);

            order.setCouponCode(null);
            orderDao.merge(order);
        }
    }


    public void payment(Order order, Payment payment, Admin operator) {
        Assert.notNull(order);
        Assert.notNull(payment);

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        payment.setOrder(order);
        paymentDao.merge(payment);
        if (payment.getMethod() == Payment.Method.deposit) {
            Member member = order.getMember();
            memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
            member.setBalance(member.getBalance().subtract(payment.getAmount()));
            memberDao.merge(member);

            Deposit.Type type = operator != null ? Deposit.Type.adminPayment : Deposit.Type.memberPayment;
            String operatorStr = (operator != null ? operator.getUsername() : null);

            depositDao.generate(type, new BigDecimal(0), order.getAmountPaid(), operatorStr, null, member, order, null);
        }

        Setting setting = SettingUtils.get();
        if (!order.getIsAllocatedStock() && setting.getStockAllocationTime() == Setting.StockAllocationTime.payment) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(true);
        }

        order.setAmountPaid(order.getAmountPaid().add(payment.getAmount()));
        order.setFee(payment.getFee());
        order.setExpire(null);
        if (order.getAmountPaid().compareTo(order.getAmount()) >= 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.paid);
        } else if (order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.partialPayment);
        }
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.payment, operator != null ? operator.getUsername() : null, order);
    }

    public void merchantPayment(Order order, Payment payment, Merchant operatorMerchant) {
        Assert.notNull(order);
        Assert.notNull(payment);

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        payment.setOrder(order);
        paymentDao.merge(payment);
        if (payment.getMethod() == Payment.Method.deposit) {
            Member member = order.getMember();
            memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
            member.setBalance(member.getBalance().subtract(payment.getAmount()));
            memberDao.merge(member);

            Deposit.Type type = operatorMerchant != null ? Deposit.Type.adminPayment : Deposit.Type.memberPayment;
            String operatorStr = (operatorMerchant != null ? operatorMerchant.getUsername() : null);

            depositDao.generate(type, new BigDecimal(0), order.getAmountPaid(), operatorStr, null, member, order, null);
        }

        Setting setting = SettingUtils.get();
        if (!order.getIsAllocatedStock() && setting.getStockAllocationTime() == Setting.StockAllocationTime.payment) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(true);
        }

        order.setAmountPaid(order.getAmountPaid().add(payment.getAmount()));
        order.setFee(payment.getFee());
        order.setExpire(null);
        if (order.getAmountPaid().compareTo(order.getAmount()) >= 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.paid);
        } else if (order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.partialPayment);
        }
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.payment, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }

    public void payment2(Order order, BigDecimal payAmount) {
        Assert.notNull(order);

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        Setting setting = SettingUtils.get();
        if (!order.getIsAllocatedStock() && setting.getStockAllocationTime() == Setting.StockAllocationTime.payment) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(true);
        }

        order.setAmountPaid(order.getAmountPaid().add(payAmount));
        order.setExpire(null);
        if (order.getAmountPaid().compareTo(order.getAmount()) >= 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.paid);
        } else if (order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
            order.setOrderStatus(OrderStatus.confirmed);
            order.setPaymentStatus(PaymentStatus.partialPayment);
        }
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.payment, null, order);
    }

    public void refunds(Order order, Refunds refunds, Admin operator) {
        Assert.notNull(order);
        Assert.notNull(refunds);

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        refunds.setOrder(order);
        refundsDao.persist(refunds);
        if (refunds.getMethod() == Refunds.Method.deposit) {
            Member member = order.getMember();
            memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
            member.setBalance(member.getBalance().add(refunds.getAmount()));
            memberDao.merge(member);

            Deposit.Type type = Deposit.Type.adminRefunds;
            String operatorStr = (operator != null ? operator.getUsername() : null);

            depositDao.generate(type, refunds.getAmount(), new BigDecimal(0), operatorStr, null, member, order, null);
        }

        order.setAmountPaid(order.getAmountPaid().subtract(refunds.getAmount()));
        order.setExpire(null);
        if (order.getAmountPaid().compareTo(new BigDecimal(0)) == 0) {
            order.setPaymentStatus(PaymentStatus.refunded);
        } else if (order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
            order.setPaymentStatus(PaymentStatus.partialRefunds);
        }
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.refunds, operator != null ? operator.getUsername() : null, order);
    }

    public void merchantRefunds(Order order, Refunds refunds, Merchant operatorMerchant) {
        Assert.notNull(order);
        Assert.notNull(refunds);

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        refunds.setOrder(order);
        refundsDao.persist(refunds);
        if (refunds.getMethod() == Refunds.Method.deposit) {
            Member member = order.getMember();
            memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
            member.setBalance(member.getBalance().add(refunds.getAmount()));
            memberDao.merge(member);

            Deposit.Type type = Deposit.Type.adminRefunds;
            String operatorStr = (operatorMerchant != null ? operatorMerchant.getUsername() : null);

            depositDao.generate(type, refunds.getAmount(), new BigDecimal(0), operatorStr, null, member, order, null);
        }

        order.setAmountPaid(order.getAmountPaid().subtract(refunds.getAmount()));
        order.setExpire(null);
        if (order.getAmountPaid().compareTo(new BigDecimal(0)) == 0) {
            order.setPaymentStatus(PaymentStatus.refunded);
        } else if (order.getAmountPaid().compareTo(new BigDecimal(0)) > 0) {
            order.setPaymentStatus(PaymentStatus.partialRefunds);
        }
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.refunds, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }

    public void shipping(Order order, Shipping shipping, Admin operator) {
        Assert.notNull(order);
        Assert.notNull(shipping);
        Assert.notEmpty(shipping.getShippingItems());

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        Setting setting = SettingUtils.get();
        if (!order.getIsAllocatedStock() && setting.getStockAllocationTime() == Setting.StockAllocationTime.ship) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(true);
        }

        shipping.setOrder(order);
        shippingDao.persist(shipping);
        for (ShippingItem shippingItem : shipping.getShippingItems()) {
            OrderItem orderItem = order.getOrderItem(shippingItem.getSn());
            if (orderItem != null) {
                Product product = orderItem.getProduct();
                productDao.lock(product, LockModeType.PESSIMISTIC_WRITE);
                if (product != null) {
                    if (product.getStock() != null) {
                        product.setStock(product.getStock() - shippingItem.getQuantity());
                        if (order.getIsAllocatedStock()) {
                            product.setAllocatedStock(product.getAllocatedStock() - shippingItem.getQuantity());
                        }
                    }
                    productDao.merge(product);
                    orderDao.flush();
                }
                orderItemDao.lock(orderItem, LockModeType.PESSIMISTIC_WRITE);
                orderItem.setShippedQuantity(orderItem.getShippedQuantity() + shippingItem.getQuantity());
            }
        }
        if (order.getShippedQuantity() >= order.getQuantity()) {
            order.setShippingStatus(ShippingStatus.shipped);
            order.setIsAllocatedStock(false);
        } else if (order.getShippedQuantity() > 0) {
            order.setShippingStatus(ShippingStatus.partialShipment);
        }
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.shipping, operator != null ? operator.getUsername() : null, order);
    }

    public void merchantShipping(Order order, Shipping shipping, Merchant operatorMerchant) {
        Assert.notNull(order);
        Assert.notNull(shipping);
        Assert.notEmpty(shipping.getShippingItems());

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        Setting setting = SettingUtils.get();
        if (!order.getIsAllocatedStock() && setting.getStockAllocationTime() == Setting.StockAllocationTime.ship) {
            deleteOrderItems(order);
            order.setIsAllocatedStock(true);
        }

        shipping.setOrder(order);
        shippingDao.persist(shipping);
        for (ShippingItem shippingItem : shipping.getShippingItems()) {
            OrderItem orderItem = order.getOrderItem(shippingItem.getSn());
            if (orderItem != null) {
                Product product = orderItem.getProduct();
                productDao.lock(product, LockModeType.PESSIMISTIC_WRITE);
                if (product != null) {
                    if (product.getStock() != null) {
                        product.setStock(product.getStock() - shippingItem.getQuantity());
                        if (order.getIsAllocatedStock()) {
                            product.setAllocatedStock(product.getAllocatedStock() - shippingItem.getQuantity());
                        }
                    }
                    productDao.merge(product);
                    orderDao.flush();
                }
                orderItemDao.lock(orderItem, LockModeType.PESSIMISTIC_WRITE);
                orderItem.setShippedQuantity(orderItem.getShippedQuantity() + shippingItem.getQuantity());
            }
        }
        if (order.getShippedQuantity() >= order.getQuantity()) {
            order.setShippingStatus(ShippingStatus.shipped);
            order.setIsAllocatedStock(false);
        } else if (order.getShippedQuantity() > 0) {
            order.setShippingStatus(ShippingStatus.partialShipment);
        }
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.shipping, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }


    public void returns(Order order, Returns returns, Admin operator) {
        Assert.notNull(order);
        Assert.notNull(returns);
        Assert.notEmpty(returns.getReturnsItems());

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        returns.setOrder(order);
        returnsDao.persist(returns);
        for (ReturnsItem returnsItem : returns.getReturnsItems()) {
            OrderItem orderItem = order.getOrderItem(returnsItem.getSn());
            if (orderItem != null) {
                orderItemDao.lock(orderItem, LockModeType.PESSIMISTIC_WRITE);
                orderItem.setReturnQuantity(orderItem.getReturnQuantity() + returnsItem.getQuantity());
                //默认已申请
                orderItem.setHasApplyReturn(true);
            }
        }
        if (order.getReturnQuantity() >= order.getShippedQuantity()) {
            order.setShippingStatus(ShippingStatus.returned);
        } else if (order.getReturnQuantity() > 0) {
            order.setShippingStatus(ShippingStatus.partialReturns);
        }
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.returns, operator != null ? operator.getUsername() : null, order);
    }

    public void merchantReturns(Order order, Returns returns, Merchant operatorMerchant) {
        Assert.notNull(order);
        Assert.notNull(returns);
        Assert.notEmpty(returns.getReturnsItems());

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        returns.setOrder(order);
        returnsDao.persist(returns);
        for (ReturnsItem returnsItem : returns.getReturnsItems()) {
            OrderItem orderItem = order.getOrderItem(returnsItem.getSn());
            if (orderItem != null) {
                orderItemDao.lock(orderItem, LockModeType.PESSIMISTIC_WRITE);
                orderItem.setReturnQuantity(orderItem.getReturnQuantity() + returnsItem.getQuantity());
                //默认已申请
                orderItem.setHasApplyReturn(true);
            }
        }
        if (order.getReturnQuantity() >= order.getShippedQuantity()) {
            order.setShippingStatus(ShippingStatus.returned);
        } else if (order.getReturnQuantity() > 0) {
            order.setShippingStatus(ShippingStatus.partialReturns);
        }
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.returns, operatorMerchant != null ? operatorMerchant.getUsername() : null, order);
    }


    @Override
    public void delete(Order order) {
        if (order.getIsAllocatedStock()) {
            deleteOrderItems(order);
        }
        super.delete(order);
    }

    @Override
    public void paymentByBalance(Order order) {
        Assert.notNull(order);

        orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);

        //用余额支付,扣除用户用于支付的积分
        Member member = order.getMember();
        BigDecimal balance = order.getAmountPayable();

        memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
        member.setBalance(member.getBalance().subtract(balance));
        memberDao.merge(member);

        distributionOrder(order);
        order.setOrderStatus(OrderStatus.confirmed);
        order.setPaymentStatus(PaymentStatus.paid);
        order.setAmountPaid(order.getAmountPaid().add(balance));
        order.setExpire(null);
        orderDao.merge(order);

        orderLogDao.generateOrderLog(Type.payment, null, order);

    }

    @Override
    public Long count(OrderStatus orderStatus, Member member, Product product, Boolean isAllocatedStock, Boolean hasExpired) {
        return orderDao.count(orderStatus, member, product, isAllocatedStock,hasExpired);
    }

    public Page<Order> findWaitingPaymentPage(Member member, Pageable pageable) {
        return orderDao.findWaitingPaymentPage(member, pageable);
    }

    public Page<Order> findWaitingShippingPage(Member member, Pageable pageable) {
        return orderDao.findWaitingShippingPage(member, pageable);
    }

    @Override
    public Page<Order> receivedPage(Member member, Pageable pageable) {
        return orderDao.receivedPage(member, pageable);
    }

    @Override
    public Page<Order> pendingEvaluationPage(Member member, Pageable pageable) {
        return orderDao.pendingEvaluationPage(member, pageable);
    }

    @Transactional
    @Override
    public void dealOrder(Charge charge, Order order) {
        try {

            Member member = order.getMember();

            //判断是否支付
//            if (charge.getPaid()) {
            if (member.getPoint().compareTo(order.getPayPoint()) >= 0) {
                distributionOrder(order);
                this.payment2(order, new BigDecimal(charge.getAmount()).divide(new BigDecimal(100)).add(order.getPayPoint()));
            } else {
                //用户积分不足,变成部分支付
                this.payment2(order, new BigDecimal(charge.getAmount()).divide(new BigDecimal(100)));
            }
            order.setPaymentMethod(findPaymentMethod(charge.getChannel()));
            this.update(order);

//            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Transactional
    public void distributionOrder(Order order) {

        GlobalConfig globalConfig = globalConfigDao.getUniqueness();

        //修改订单信息,更新订单
        order.setInvoiceTitle("" + order.getId());

        Member member = order.getMember();


        // 会员推荐主播（上级）
        Member parentMember = member.getParent();
        // 会员推荐商家（上级）
        Merchant parentMerchant = member.getParentMerchant();

        // 会员推荐主播的推荐主播（上上级）
        Member parentMemberMember = null;
        // 会员推荐主播的推荐商家（上上级）
        Merchant parentMemberMerchant = null;

        if (parentMember != null && parentMember.getParentCode() != null && parentMember.getParentCode().startsWith(Constant.MERCHANT_CODE_BEGIN)) {
            parentMemberMerchant = parentMember.getParentMerchant();
        }
        if (parentMember != null && parentMember.getParentCode() != null && parentMember.getParentCode().startsWith(Constant.MEMBER_CODE_BEGIN)) {
            parentMemberMember = parentMember.getParent();
        }

        // 订单的拥有商家
        Merchant orderMerchant = order.getMerchant();
        Platform platform = platformDao.getUniqueness();

        // 用户积分足够
        // 扣除用户使用的积分，将积分转到平台或者订单的拥有商家


        member.setPoint(member.getPoint().subtract(order.getPayPoint()));

        // 订单总计
        BigDecimal orderBalance = order.getAmountPayable();

        // 利润比例：自营 是 0 ， 商家是 orderMerchant.getProportion()
        BigDecimal proportion = null;

        if (orderMerchant == null) {
            // 自营
            platform.setPoint(platform.getPoint().add(order.getPayPoint()));
            proportion = new BigDecimal(0);
        } else {
            // 商家 获得 订单价*（1-商家抽佣比例），分润以外的金额归商家拥有
            BigDecimal merchantBalance = orderBalance.multiply((new BigDecimal(1)).subtract(orderMerchant.getProportion()));
            orderMerchant.setBalance(orderMerchant.getBalance().add(merchantBalance));
            proportion = orderMerchant.getProportion();
        }

        // 分润  =  100元总价-60积分 = 40元现金 * 10% 利润
        BigDecimal shareAmount = orderBalance.multiply(proportion);

        // 主播分润
        List<AnchorTrade> anchorTrades = new ArrayList<>();
        for (OrderItem orderItem : order.getOrderItems()) {
            Member anchor = orderItem.getAnchor();
            if (anchor != null) {
                // 订单项/总价 * 分润
                BigDecimal proportionOfSub = orderItem.getSubtotal().divide(orderBalance, 2, BigDecimal.ROUND_HALF_UP);
                BigDecimal subAmount = proportionOfSub.multiply(shareAmount).multiply(globalConfig.getAnchorLevel());
                anchor.setBalance(anchor.getBalance().add(subAmount));
                AnchorTrade anchorTrade = new AnchorTrade(
                        order.getSn(),
                        anchor,
                        subAmount,
                        member,
                        orderItem.getFullName()
                );
                anchorTrades.add(anchorTrade);
                shareAmount = shareAmount.subtract(subAmount);
            }
        }

        // 上级分润
        BigDecimal parentFirstAmount = shareAmount.multiply(globalConfig.getFirstParent());
        // 上上级分润
        BigDecimal parentSecondAmount = shareAmount.multiply(globalConfig.getSecondParent());
        // 获得积分
        BigDecimal memberPoint = orderBalance.multiply(globalConfig.getPointProportion());

        member.setPoint(member.getPoint().add(memberPoint));

        BigDecimal trade_member_parent_balance = new BigDecimal(0);
        BigDecimal trade_member_merchant_balance = new BigDecimal(0);
        BigDecimal trade_member_parent_merchant_balance = new BigDecimal(0);
        BigDecimal trade_member_parent_member_balance = new BigDecimal(0);
        BigDecimal trade_platform_balance = new BigDecimal(0);

        if (parentMerchant != null) {

            parentMerchant.setBalance(parentMerchant.getBalance().add(parentFirstAmount));

            trade_member_merchant_balance = parentFirstAmount;
            trade_platform_balance = shareAmount.subtract(parentFirstAmount);

        } else if (parentMember != null) {

            parentMember.setBalance(parentMember.getBalance().add(parentFirstAmount));

            trade_member_parent_balance = parentFirstAmount;
            trade_platform_balance = shareAmount.subtract(parentFirstAmount);

        }

        if (parentMember != null && parentMemberMember != null) {
            parentMemberMember.setBalance(parentMemberMember.getBalance().add(parentSecondAmount));

            trade_member_parent_member_balance = parentSecondAmount;
            trade_platform_balance = trade_platform_balance.subtract(parentSecondAmount);

        } else if (parentMember != null && parentMemberMerchant != null) {
            parentMemberMerchant.setBalance(parentMemberMerchant.getBalance().add(parentSecondAmount));

            trade_member_parent_merchant_balance = parentSecondAmount;
            trade_platform_balance = trade_platform_balance.subtract(parentSecondAmount);

        }
        if (parentMember != null) memberDao.merge(parentMember);
        if (parentMemberMerchant != null) merchantDao.merge(parentMemberMerchant);
        if (orderMerchant != null) merchantDao.merge(orderMerchant);
        if (platform != null) platformDao.merge(platform);

        PointTrade pointTrade = new PointTrade(
                order.getSn(),
                order.getPayPoint(),
                order.getAmountPayable(),
                proportion,
                member,
                parentMember,
                parentMemberMerchant,
                parentMemberMember,
                parentMerchant,
                memberPoint,
                trade_member_parent_balance,
                trade_member_merchant_balance,
                trade_member_parent_merchant_balance,
                trade_member_parent_member_balance,
                trade_platform_balance
        );
        pointTrade.setMerchant(member.getMerchant());
        pointTrade = pointTradeDao.merge(pointTrade);
        memberDao.merge(member);
        // 持久化主播端的分佣
        for (AnchorTrade anchorTrade : anchorTrades) {
            anchorTrade.setPointTrade(pointTrade);
            anchorTradeDao.merge(anchorTrade);
        }
    }

    /**
     * 删除订单对应订单项
     *
     * @param order
     */
    private void deleteOrderItems(Order order) {
        for (OrderItem orderItem : order.getOrderItems()) {
            if (orderItem != null) {
                Product product = orderItem.getProduct();
                productDao.lock(product, LockModeType.PESSIMISTIC_WRITE);
                if (product != null && product.getStock() != null) {
                    product.setAllocatedStock(product.getAllocatedStock() - (orderItem.getQuantity() - orderItem.getShippedQuantity()));
                    productDao.merge(product);
                    orderDao.flush();
                }
            }
        }
    }


    /**
     * 查找对应的支付方式
     */
    private PaymentMethod findPaymentMethod(String channel) {

        List<PaymentMethod> paymentMethods = paymentMethodDao.findList(null, null, null, null);
        HashMap<String, Integer> modeOfPayment = new HashMap<>();
        modeOfPayment.put(Constants.CHANNEL_WX, 0);
        modeOfPayment.put(Constants.CHANNEL_ALIPAY, 1);
        modeOfPayment.put(Constants.CHANNEL_UPACP, 2);
        modeOfPayment.put(Constants.CHANNEL_AMOUNT_PAY, 3);
        return paymentMethods.get(modeOfPayment.get(channel));
    }
}